package org.lisy.java.thread;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * 循环栅栏
 * 
 * @author lisy
 */
public class CyclicBarrierOperate {

	/**
	 * await(): 线程调用表示已经到达栅栏
	 * BrokenBarrierException: 表示栅栏已经被破坏，破坏的原因可能是其中一个线程 await() 时被中断或者超时
	 * 使用场景: 合并计算
	 */
    static class TaskThread extends Thread {
        
        CyclicBarrier barrier;
        
        public TaskThread(CyclicBarrier barrier) {
            this.barrier = barrier;
        }
        
        @Override
        public void run() {
            try {
            	TimeUnit.SECONDS.sleep(1);
                System.out.println(getName() + " arrive barrier A");
				barrier.await();
                System.out.println(getName() + " overgo barrier A");
                if ("Thread-0".equals(getName())) {
                	TimeUnit.SECONDS.sleep(2);
                } else {
                	TimeUnit.SECONDS.sleep(5);
                }
                System.out.println(getName() + " arrive barrier B");
                barrier.await(2, TimeUnit.SECONDS);
                System.out.println(getName() + " overgo barrier B");
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (BrokenBarrierException e) {
				e.printStackTrace();
				System.out.println("栅栏已经被破坏，破坏的原因可能是其中一个线程 await() 时被中断或者超时!");
			} catch (TimeoutException e) {
				e.printStackTrace();
				System.out.println("栅栏 await() 超时!");
			}
        }
    }
    
    public static void main(String[] args) {
    	/**
    	 * parties: 参与线程的个数
    	 * barrierAction: Runnable 参数，最后一个到达线程要做的任务
    	 */
        CyclicBarrier barrier = new CyclicBarrier(5, new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " await task!");
            }
        });
        
        for(int i = 0; i < 5; i++) {
            new TaskThread(barrier).start();
        }
    }
    
}